package wxpay

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"strings"
	"time"
)

// GenerateNonceStr 生成随机字符串
func GenerateNonceStr() string {
	return fmt.Sprintf("%d", time.Now().UnixNano())
}

// GenerateSign 生成签名
func GenerateSign(params map[string]string, apiKey string) string {
	// 1. 参数名ASCII码从小到大排序
	var keys []string
	for k := range params {
		if k == "sign" {
			continue
		}
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// 2. 拼接字符串
	var builder strings.Builder
	for _, k := range keys {
		if params[k] == "" {
			continue
		}
		builder.WriteString(k)
		builder.WriteString("=")
		builder.WriteString(params[k])
		builder.WriteString("&")
	}
	builder.WriteString("key=")
	builder.WriteString(apiKey)

	// 3. MD5加密并转大写
	h := md5.New()
	h.Write([]byte(builder.String()))
	return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}

// MapToXML 将map转换为XML
func MapToXML(params map[string]string) (string, error) {
	var builder strings.Builder
	builder.WriteString("<xml>")
	for k, v := range params {
		builder.WriteString("<")
		builder.WriteString(k)
		builder.WriteString(">")
		builder.WriteString(v)
		builder.WriteString("</")
		builder.WriteString(k)
		builder.WriteString(">")
	}
	builder.WriteString("</xml>")
	return builder.String(), nil
}

// XMLToMap 将XML转换为map
func XMLToMap(xmlStr string) (map[string]string, error) {
	params := make(map[string]string)
	err := xml.Unmarshal([]byte(xmlStr), (*map[string]string)(&params))
	if err != nil {
		return nil, err
	}
	return params, nil
}

// SendHTTPPost 发送HTTP POST请求
func SendHTTPPost(url string, data string) ([]byte, error) {
	resp, err := http.Post(url, "application/xml; charset=utf-8", strings.NewReader(data))
	if err != nil {
		return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应内容失败: %v", err)
	}
	return body, nil
}

// VerifySign 验证签名
func VerifySign(params map[string]string, apiKey string) bool {
	sign := params["sign"]
	delete(params, "sign")
	return sign == GenerateSign(params, apiKey)
}
